package com.company.dcm.server.protocol;

import com.company.dcm.server.protocol.enums.ProtocolMessageTypeEnum;
import com.company.dcm.server.protocol.enums.ProtocolTaskOptionEnum;
import io.netty.buffer.ByteBuf;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: 王泽同
 * @Description: 消息解码器
 */
public class ProtocolMessageDecoder {

    public static ProtocolMessage decode(ByteBuf buffer) throws IOException {
        // 分别从指定位置读出 ByteBuf
        ProtocolMessage.Header header = new ProtocolMessage.Header();
        ProtocolMessage.Tail tail = new ProtocolMessage.Tail();

        // 获取起始魔数
        header.setStartMagic(buffer.getByte(0));

        // 校验魔数
        if (header.getStartMagic()!= ProtocolConstant.START_MAGIC) {
            throw new RuntimeException("消息起始 magic 非法");
        }

        // 获取版本号
        header.setVersion(buffer.getByte(1));

        // 获取帧长度（从1起）
        header.setLength(buffer.getShort(2));

        // 获取帧类型
        header.setType(ProtocolMessageTypeEnum.getEnumByValue(buffer.getByte(4)));

        // 解决粘包问题，只读指定长度的数据（除2位校验位 + 1位终结符+前5位）
        byte[] bodyBytes = new byte[header.getLength() - 8];
        buffer.getBytes(5, bodyBytes);

        // 生成任务列表
        List<ProtocolTask> taskList = bytes2ProtocolTaskBytesList(header.getType(),bodyBytes);

        // 获取校验值
        tail.setParity(buffer.getShort(header.getLength() - 2 - 1));

        // 获取结尾魔数
        tail.setEndMagic(buffer.getByte(header.getLength() - 1));

        // 校验魔数
        if (tail.getEndMagic()!= ProtocolConstant.END_MAGIC) {
            throw new RuntimeException("消息结尾 magic 非法");
        }

        return new ProtocolMessage(header, taskList, tail);
    }


    private static List<ProtocolTask> bytes2ProtocolTaskBytesList(ProtocolMessageTypeEnum messageType,byte[] bytes){
        try {
            if (bytes.length<2){
                throw new RuntimeException("消息body长度非法");
            }
            int index = 0;
            List<ProtocolTask> list = new ArrayList<>();

            while(index< bytes.length - 1){
                ProtocolTask task = new ProtocolTask();
                task.setOption(ProtocolTaskOptionEnum.getEnumByTypeAndValue(messageType.getValue(),bytes[index]));
                index ++;
                task.setValueType(bytes[index]);
                index ++;
                byte lowFourBits = (byte) (task.getValueType() & 0x0F);
                if(lowFourBits==5)
                {
                    task.setLength(bytes[index]);
                    index ++;
                }
                else if(lowFourBits==6) {
                    byte a=bytes[index ++ ];
                    byte b=bytes[index ++ ];
                    ByteBuffer buffer=ByteBuffer.allocate(2);
                    buffer.put(a);
                    buffer.put(b);
                    buffer.flip();
                    short length=buffer.getShort();
                    task.setLength(length);
                }else if(lowFourBits==0||lowFourBits==1){
                    task.setLength(1);
                }
                else if(lowFourBits==2||lowFourBits==3||lowFourBits==4){
                    task.setLength(4);
                } else if (lowFourBits == 8) {
//                    task.setLength();
                }
                byte[] valueBytes = new byte[task.getLength()];
                for (int i = 0; i < task.getLength(); i++) {
                    valueBytes[i]=bytes[index ++ ];
                }
                task.setValues(valueBytes);

                list.add(task);
            }

            return list;
        }catch (NullPointerException e){
            throw new RuntimeException("消息body内部长度非法");
        }
    }
}
